#pragma once

#include <iostream>
#include <pthread.h>
#include <queue>

template<class T>
class BlockQueue
{
private:
    std::queue<T> _block_queue;
    int _productor_wait_num;
    int _consumer_wait_num;
    unsigned int _cap;
    pthread_mutex_t _mutex;
    pthread_cond_t _productor_cond;
    pthread_cond_t _consumer_cond;
private:
    //判断队列空和满的函数
    bool isEmpty()
    {
        return _block_queue.empty();
    }
    bool isFull()
    {
        return _block_queue.size()==_cap;
    }
public:
    BlockQueue(unsigned int cap)
        :_cap(cap)
        ,_productor_wait_num(0)
        ,_consumer_wait_num(0)
    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_productor_cond,nullptr);
        pthread_cond_init(&_consumer_cond,nullptr);
    }
    //生产者用的接口
    void Enqueue(const T& in)
    {
        pthread_mutex_lock(&_mutex);
        while(isFull())
        {
            _productor_wait_num++;
            pthread_cond_wait(&_productor_cond,&_mutex);
            _productor_wait_num--;
        }
        _block_queue.push(in);
        //通知消费者可以消费了
        if(_consumer_wait_num>0)
            pthread_cond_signal(&_consumer_cond);
        pthread_mutex_unlock(&_mutex);
    }

    //消费者用的接口
    void Pop(T* out)
    {
        pthread_mutex_lock(&_mutex);
        while(isEmpty())
        {
            _consumer_wait_num++;
            pthread_cond_wait(&_consumer_cond,&_mutex);
            _consumer_wait_num--;
        }
        *out=_block_queue.front();
        _block_queue.pop();
        //有位置了，通知生产者可以生产了
        if(_productor_wait_num>0)
            pthread_cond_signal(&_productor_cond);
        pthread_mutex_unlock(&_mutex);
    }
    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_productor_cond);
        pthread_cond_destroy(&_consumer_cond);
    }
};